{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# More features for ```Experiment``` class: custom config, `Measurable` parameter, `analysis` function\n",
    "\n",
    "This example uses the ```Experiment``` class to create a measurement from a ```procedure``` object, with the ```Measurable``` parameter to automatically generate sorted ```DATA_COLUMNS``` and ```MEASURE``` lists (which is then passed to the ```get_datapoint``` function of the ```Procedure``` class).\n",
    "\n",
    "The file ```my_config.ini``` is passed to set custom data saving, logging and matplotlib options.\n",
    "\n",
    "The ```analysis``` function is passed as an optional attribute, to produce on-the-fly data analysis for live plotting (only the raw data is saved on disk). To have analysed data save on disk, create an empty ```Measurable``` and update it in the ```measure``` loop as also shown in the example below."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%writefile my_config.ini\n",
    "[Filename]\n",
    "prefix = my_data_\n",
    "dated_folder = 1\n",
    "directory = data\n",
    "ext = csv\n",
    "index = \n",
    "datetimeformat = %Y%m%d_%H%M%S\n",
    "\n",
    "[Logging]\n",
    "console = 1\n",
    "console_level = WARNING\n",
    "filename = test.log\n",
    "file_level = DEBUG\n",
    "\n",
    "[matplotlib.rcParams]\n",
    "axes.axisbelow = True\n",
    "axes.prop_cycle = cycler('color', ['b', 'g', 'r', 'c', 'm', 'y', 'k'])\n",
    "axes.edgecolor = 'white'\n",
    "axes.facecolor = '#EAEAF2'\n",
    "axes.grid = True\n",
    "axes.labelcolor = '.15'\n",
    "axes.labelsize = 11.0\n",
    "axes.linewidth = 0.0\n",
    "axes.titlesize = 12.0\n",
    "figure.facecolor = 'white'\n",
    "figure.figsize = [8.0, 5.5]\n",
    "font.sans-serif = ['Arial', 'Liberation Sans', 'Bitstream Vera Sans', 'sans-serif']\n",
    "grid.color = 'white'\n",
    "grid.linestyle = '-'\n",
    "grid.linewidth = 1.0\n",
    "image.cmap = 'Greys'\n",
    "legend.fontsize = 10.0\n",
    "legend.frameon = False\n",
    "legend.numpoints = 1\n",
    "legend.scatterpoints = 1\n",
    "lines.linewidth = 1.75\n",
    "lines.markeredgewidth = 0.0\n",
    "lines.markersize = 7.0\n",
    "lines.solid_capstyle = 'round'\n",
    "patch.facecolor = (0.2980392156862745, 0.4470588235294118, 0.6901960784313725)\n",
    "patch.linewidth = 0.3\n",
    "text.color = '.15'\n",
    "xtick.color = '.15'\n",
    "xtick.direction = 'out'\n",
    "xtick.labelsize = 10.0\n",
    "xtick.major.pad = 7.0\n",
    "xtick.major.size = 0.0\n",
    "xtick.major.width = 1.0\n",
    "xtick.minor.size = 0.0\n",
    "ytick.color = '.15'\n",
    "ytick.direction = 'out'\n",
    "ytick.labelsize = 10.0\n",
    "ytick.major.pad = 7.0\n",
    "ytick.major.size = 0.0\n",
    "ytick.major.width = 1.0\n",
    "ytick.minor.size = 0.0"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%writefile procedures.py\n",
    "import random\n",
    "from time import sleep\n",
    "\n",
    "import logging\n",
    "log = logging.getLogger('')\n",
    "log.addHandler(logging.NullHandler())\n",
    "\n",
    "from pymeasure.experiment import Procedure, IntegerParameter, Parameter, FloatParameter, Measurable\n",
    "\n",
    "class TestProcedure(Procedure):\n",
    "    \n",
    "    iterations = IntegerParameter('Loop Iterations', default=100)\n",
    "    delay = FloatParameter('Delay Time', units='s', default=0.2)\n",
    "    seed = Parameter('Random Seed', default='12345')\n",
    "    iteration = Measurable('Iteration', default = 0)\n",
    "    random_number = Measurable('Random Number', random.random)\n",
    "    offset = Measurable('Random Number + 1', default = 0)\n",
    "\n",
    "    def startup(self):\n",
    "        log.info(\"Setting up random number generator\")\n",
    "        random.seed(self.seed)\n",
    "        \n",
    "    def measure(self):\n",
    "        data = self.get_datapoint()\n",
    "        data['Random Number + 1'] = data['Random Number'] + 1\n",
    "        log.debug(\"Produced numbers: %s\" % data)\n",
    "        self.emit('results', data)\n",
    "        self.emit('progress', 100.*self.iteration.value/self.iterations)\n",
    "\n",
    "    def execute(self):\n",
    "        log.info(\"Starting to generate numbers\")\n",
    "        for self.iteration.value in range(self.iterations):\n",
    "            self.measure()\n",
    "            sleep(self.delay)\n",
    "            if self.should_stop():\n",
    "                log.warning(\"Catch stop command in procedure\")\n",
    "                break\n",
    "\n",
    "    def shutdown(self):\n",
    "        log.info(\"Finished\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%writefile analysis.py\n",
    "def add_offset(data, offset):\n",
    "    return data['Random Number'] + offset\n",
    "\n",
    "def analyse(data):\n",
    "    data['Random Number + 2'] = add_offset(data, 2)\n",
    "    return data"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from pymeasure.experiment import Experiment, config\n",
    "from procedures import TestProcedure\n",
    "from analysis import analyse\n",
    "config.set_file('my_config.ini')\n",
    "%matplotlib inline"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "scrolled": true
   },
   "outputs": [],
   "source": [
    "procedure = TestProcedure(iterations=10, delay=.1)\n",
    "experiment = Experiment('test', procedure, analyse)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "experiment.start()\n",
    "import pylab as pl\n",
    "pl.figure(figsize=(10,4))\n",
    "ax1 = pl.subplot(121)\n",
    "experiment.plot('Iteration', 'Random Number', ax=ax1)\n",
    "ax2 = pl.subplot(122)\n",
    "experiment.plot('Iteration', 'Random Number + 1', ax=ax2)\n",
    "experiment.plot_live()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Analysed data"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "experiment.data"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Raw data (as saved on disk)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "scrolled": true
   },
   "outputs": [],
   "source": [
    "experiment.results.data"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Filename generated by config preferences"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "experiment.filename"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.9"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 1
}
